#!/usr/bin/python
#-*- coding: utf-8 -*-
import re
import os, sys
from os.path import abspath, dirname, getmtime, exists
from pyinotify import *
from optparse import OptionParser
flags = IN_CREATE|IN_MODIFY|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO
efilter = re.compile(r"/\..*").search


def become_daemon(out="/dev/null", err="/dev/null", home_dir=".", umask=022):
    # First fork
    try: 
        if os.fork() > 0: 
            sys.exit(0)
    except OSError, e:
        sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
        sys.exit(1)
    os.setsid()
    os.chdir(home_dir)
    os.umask(umask)

    # Second fork
    try: 
        if os.fork() > 0: 
            os._exit(0)
    except OSError, e:
        sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
        os._exit(1)
    si = open('/dev/null', 'r') 
    so = open(out, 'a+', 0)
    se = open(err, 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())
    # Set custom file descriptors so that they get proper buffering.
    sys.stdout, sys.stderr = so, se


class UpdateParentDir(ProcessEvent):
    def my_init(self, **kargs):
        self.base = kargs["base"]
        self.exclude_filters = kargs.get("exclude_filters", [])

    def __call__(self, event):
        for exclude_filter in self.exclude_filters:
            if exclude_filter(event.pathname):
                return
        ProcessEvent.__call__(self, event)

    def process_IN_MODIFY(self, event):
        if not options.quiet:
            print event
        #if not exists(event.pathname): return
        #mtime = getmtime(event.pathname)
        p = event.path
        while p.startswith(self.base):
            try: os.utime(p, None)
            except OSError: pass
            p = dirname(p)
    process_IN_MOVED_TO = process_IN_MODIFY
    process_IN_CREATE = process_IN_MODIFY
    process_IN_DELETE = process_IN_MODIFY
    process_IN_MOVED_FROM = process_IN_MODIFY

    def process_default(self, event):
        if not options.quiet:
            print "unhandle", event


if __name__ == "__main__":
    parser = OptionParser(usage="usage: %prog [-dq] [dir] ...")
    parser.add_option("-d", "--daemon",
            dest="daemon",
            action="store_true",
            default=False,
            help="run the script as a daemon")
    parser.add_option("-q", "--quiet",
            dest="quiet",
            action="store_true",
            default=False,
            help="don't print log message")
    options, args = parser.parse_args()
    if options.daemon:
        become_daemon()
    wm = WatchManager()
    notifier = Notifier(wm)
    for base in args:
        base = abspath(base)
        update_parent_dir = UpdateParentDir(base=base, exclude_filters=[efilter])
        wm.add_watch(base, flags, update_parent_dir, rec=True, auto_add=True)
    notifier.loop()
